package com.blogSystem.article.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.blogSystem.article.client.UserClient;
import com.blogSystem.article.dao.*;
import com.blogSystem.article.pojo.*;

import com.blogSystem.article.util.Predict;
import entity.PageResult;
import org.jetbrains.annotations.NotNull;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import util.IdWorker;
import util.SetPriority;

import javax.persistence.criteria.*;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

@Service
@Transactional
public class ArticleService {
    @Autowired
    private ArticleDao articleDao;

    @Autowired
    private ViewMapper viewMapper;

    @Autowired
    private UserClient userClient;

    @Autowired
    private CategoryMapper categoryMapper;

    @Autowired
    private ThumbsMapper thumbsMapper;

    @Autowired
    private LabelMapper labelMapper;

    @Autowired
    private DefineMapper defineMapper;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired(required = false)
    public void setRedisTemplate(RedisTemplate redisTemplate) {
        RedisSerializer stringSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setValueSerializer(stringSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        redisTemplate.setHashValueSerializer(stringSerializer);
        this.redisTemplate = redisTemplate;
    }


    //查询所有文章
    public List<Article> findAll() {
        return articleDao.findAll();
    }


    public Article findById(String _id) {
        return articleDao.findById(_id).get();
    }

    //分页查询所有文章
    public Page<Article> findAllAndPage(int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);
        return articleDao.findAll(pageable);
    }

    //根据作者查询文章并且分页
    public Page<Article> findByAuthorAndPage(String author, int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);

        return articleDao.findByAuthor(pageable, author);
    }

    //根据作者模糊查询并且分页
    public Page<Article> findByAuthorLike(String author, int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);

        return articleDao.findByAuthorLike(pageable, author);
    }

    //根据类别查询文章并且分页
    public Page<Article> findByTypeAndPage(String type, int page, int size) {

        Pageable pageable = PageRequest.of(page - 1, size);

        return articleDao.findByType(pageable, type);
    }

    //根据文章作者模糊查询
    public Page<Article> findByTitle(String title, int page, int size) {

        Pageable pageable = PageRequest.of(page - 1, size);
        return articleDao.findByTitleLike(pageable, title);
    }

    //根据标签查询文章并且分页
    public Page<Article> findByLabelAndPage(String label, int page, int size) {

        Pageable pageable = PageRequest.of(page, size);

        return articleDao.findByLabelsContains(pageable, label);
    }

    //给据类别查询并且分页
    public Page<Article> findByCategoryAndPage(String category,int page,int size){
        Pageable pageable= PageRequest.of(page,size);

        return articleDao.findAllByCategoryAndState(pageable,category,1);

    }
    //添加浏览记录
    public void addViewRecord(String user_id,String category_id){

        View view=new View();
        view.setCategory_id(category_id);
        view.setUser_id(user_id);
        if (viewMapper.selectById(view)==null){
            view.setCount(1);
            view.setLately(new Date());
            viewMapper.insert(view);
        }
        else{
            View get=viewMapper.selectById(view);
            int count=get.getCount();
            view.setCount(count+1);
            view.setLately(new Date());
            viewMapper.update(view);
        }


    }

    //储存文章
    public void save(Article article) {
      String id=idWorker.nextId() + "";
        article.set_id(id);
        article.setCount(0);
        article.setState(0);
        article.setThumbs(0);

        article.setUploadTime(new Date());
      //  Category category=categoryMapper.selectByType(article.getCategory());
       // article.setCategory(category.getId());
        //储存分类，由于分类需要较长时间，需要用消息队列处理

        Map <String,String> map=new HashMap<String ,String>();
        map.put("_id",article.get_id());
        map.put("text",article.getText());

        rabbitTemplate.convertAndSend("article",map);
        articleDao.save(article);
    }

    //修改文章
    public void update(Article article) {
        articleDao.save(article);
    }

    //删除文章
    public void deleteById(String _id) {
        articleDao.deleteById(_id);
        thumbsMapper.deleteByArticleId(_id);
    }

    //查询未审核的文章列表
    public Page<Article> findNotReview(int page, int size) {

        Pageable pageable = PageRequest.of(page - 1, size);



        return articleDao.findByState(pageable, 0);

    }


    //查询已审核的文章列表
    public Page<Article> findReviewed(int page, int size) {

        Pageable pageable = PageRequest.of(page - 1, size);

        return articleDao.findByState(pageable, 1);

    }

    //审核文章
    public void review(String _id){
        Article article=articleDao.findById(_id).get();
        article.setState(1);
        articleDao.save(article);
    }

    //添加类型
    public void add_type(String _id,String type_id){
        Article article=articleDao.findById(_id).get();
        if(article!=null){
            article.setType(type_id);
            articleDao.save(article);
        }

    }

    //未登录用户的匹配措施
    public List<Article> NotLogMatching(){


        //查询所有的列表
        List<Article> articles=articleDao.findAllByState(1);
        //按发表时间排序
        List<Article> timesort=articleDao.findAllByState(1, Sort.by(Sort.Order.desc("uploadTime")));
        //定义优先级队列
        PriorityQueue priorityQueue=new PriorityQueue();
        //将所有文章赋予优先级，默认100
        for(Article article:articles){
            SetPriority<Article> articleSetPriority=new SetPriority<Article>();
            articleSetPriority.setObject(article);
            priorityQueue.add(articleSetPriority);
        }

        //按照点赞次数赋予，为0则不操作
        for (Article article:articles){

            if (article.getThumbs()!=0){
                //储存对象的列表
                List <SetPriority> list=new ArrayList<SetPriority>();
                //优先级队列的长度应该等于查询的列表的长度
                for (int i=0;i<articles.size();i++) {
                    //获取并删除队首元素
                    SetPriority setPriority= (SetPriority) priorityQueue.remove();
                    //获取对象信息
                    Article o= (Article) setPriority.getObject();
                    //对每个对象进行优先级增加
                    if(o.get_id().equals(article.get_id())) {

                        setPriority.addPriorityLevel2(article.getThumbs()/2);
                        //再次储存此对象
                        priorityQueue.add(setPriority);
                        //将之前删除的对象重新储存
                        if(!list.isEmpty()){
                            for(SetPriority priority:list){
                                priorityQueue.add(priority);
                            }
                        }
                        break;
                    }
                    //储存当前被删除信息到列表中
                    list.add(setPriority);
                }
                if (priorityQueue.size()==0){
                    if (!list.isEmpty()) {
                        for (SetPriority priority : list) {
                            priorityQueue.add(priority);
                        }
                    }
                    break;
                }

            }


        }

        //按照浏览次数赋予

        for (Article article:articles){

            if (article.getCount()!=0){
                List <SetPriority> list=new ArrayList<SetPriority>();

                for (int i=0;i<articles.size();i++){
                    SetPriority setPriority= (SetPriority) priorityQueue.remove();
                    Article o= (Article) setPriority.getObject();
                    if(o.get_id().equals(article.get_id())) {
                        setPriority.addPriorityLevel1(article.getCount()/2);
                        priorityQueue.add(setPriority);
                        if(!list.isEmpty()){
                            for(SetPriority priority:list){
                                priorityQueue.add(priority);
                            }
                        }
                        break;
                    }
                    list.add(setPriority);
                }
                if (priorityQueue.size()==0){
                    if (!list.isEmpty()) {
                        for (SetPriority priority : list) {
                            priorityQueue.add(priority);
                        }
                    }
                    break;
                }

            }


        }
        //获取最后20%的时间发表的文章

        List<Article> timesort_define=timesort.subList(0,timesort.size()/5);

        //按照时间赋予，后发布的优先级高
        for(Article article:timesort_define) {
            List<SetPriority> list = new ArrayList<SetPriority>();
            for (int i = 0; i < articles.size(); i++) {
                SetPriority setPriority = (SetPriority) priorityQueue.remove();
                Article o = (Article) setPriority.getObject();

                if (o.get_id().equals(article.get_id())) {
                    setPriority.addPriorityLevel3(2);
                    priorityQueue.add(setPriority);
                    if (!list.isEmpty()) {
                        for (SetPriority priority : list) {
                            priorityQueue.add(priority);
                        }
                    }
                    break;
                }
                list.add(setPriority);
            }
            if (priorityQueue.size()==0){
                if (!list.isEmpty()) {
                    for (SetPriority priority : list) {
                        priorityQueue.add(priority);
                    }
                }
                break;
            }
        }
        //获取2小时内浏览次数，如果有记录则下降优先级
        for(Article article:articles) {
            List<SetPriority> list = new ArrayList<SetPriority>();
            for (int i = 0; i < articles.size(); i++) {
                SetPriority setPriority = (SetPriority) priorityQueue.remove();
                Article o = (Article) setPriority.getObject();

                if(redisTemplate.opsForValue().get("article_"+o.get_id())!=null){
                    Integer count= Integer.parseInt((String) redisTemplate.opsForValue().get("article_"+o.get_id()));
                    setPriority.declinePriorityLevel3(count);
                    priorityQueue.add(setPriority);
                    if (!list.isEmpty()) {
                        for (SetPriority priority : list) {
                            priorityQueue.add(priority);
                        }
                    }
                    break;
                }
                list.add(setPriority);
            }
            //可能出现空队列的情况
            if (priorityQueue.size()==0){
                    if (!list.isEmpty()) {
                        for (SetPriority priority : list) {
                            priorityQueue.add(priority);
                        }
                    }
                    break;
            }
        }

        //只返回前10条数据
        int record=articles.size();
        if(record>=10){
            record=10;
        }
        List<Article> articleList=new ArrayList<Article>();
        for(int i=0;i<record;i++){
            SetPriority setPriority= (SetPriority) priorityQueue.remove();
            Article o= (Article) setPriority.getObject();
            //记录浏览次数到redis
            if (redisTemplate.opsForValue().get("article_"+o.get_id())==null){
                Integer count=1;
                redisTemplate.opsForValue().set("article_"+o.get_id(),count.toString(),2, TimeUnit.HOURS);
            }
            else{

                Integer count= Integer.parseInt((String) redisTemplate.opsForValue().get("article_"+o.get_id()));
                count=count+1;
                String string = count.toString();
                System.out.println(string);
                System.out.println(string);
                long ttl=redisTemplate.getExpire("article_"+o.get_id());
                System.out.println(ttl);
                redisTemplate.opsForValue().set("article_"+o.get_id(),string,ttl,TimeUnit.SECONDS);

            }
            articleList.add(o);
        }

        return articleList;
    }

//已登录用户匹配
    public List<Article> userMatching(List <String> jsons,String user_id){

        //查询所有的列表
        List<Article> articles=articleDao.findAllByState(1);


        //按发表时间排序
        List<Article> timesort=articleDao.findAllByState(1, Sort.by(Sort.Order.desc("uploadTime")));
        //List
        //定义优先级队列
        PriorityQueue priorityQueue=new PriorityQueue();
        //将所有文章赋予优先级，默认100
        for(Article article:articles){
            SetPriority<Article> articleSetPriority=new SetPriority<Article>();
            articleSetPriority.setObject(article);
            priorityQueue.add(articleSetPriority);
        }

        //按照点赞次数赋予，为0则不操作
        for (Article article:articles){

            if (article.getThumbs()!=0){
                //储存对象的列表
                List <SetPriority> list=new ArrayList<SetPriority>();
                //优先级队列的长度应该等于查询的列表的长度
                for (int i=0;i<articles.size();i++) {
                    //获取并删除队首元素
                    SetPriority setPriority= (SetPriority) priorityQueue.remove();
                    //获取对象信息
                    Article o= (Article) setPriority.getObject();
                    //对每个对象进行优先级增加
                    if(o.get_id().equals(article.get_id())) {

                        setPriority.addPriorityLevel2(article.getThumbs()/2);
                        //再次储存此对象
                        priorityQueue.add(setPriority);
                        //将之前删除的对象重新储存
                        if(!list.isEmpty()){
                            for(SetPriority priority:list){
                                priorityQueue.add(priority);
                            }
                        }
                        break;
                    }
                    //储存当前被删除信息到列表中
                    list.add(setPriority);
                }
                if (priorityQueue.size()==0){
                    if (!list.isEmpty()) {
                        for (SetPriority priority : list) {
                            priorityQueue.add(priority);
                        }
                    }
                    break;
                }

            }


        }

        //按照浏览次数赋予

        for (Article article:articles){

            if (article.getCount()!=0){
                List <SetPriority> list=new ArrayList<SetPriority>();

                for (int i=0;i<articles.size();i++){
                    SetPriority setPriority= (SetPriority) priorityQueue.remove();
                    Article o= (Article) setPriority.getObject();
                    if(o.get_id().equals(article.get_id())) {
                        setPriority.addPriorityLevel1(article.getCount()/2);
                        priorityQueue.add(setPriority);
                        if(!list.isEmpty()){
                            for(SetPriority priority:list){
                                priorityQueue.add(priority);
                            }
                        }
                        break;
                    }
                    list.add(setPriority);
                }
                if (priorityQueue.size()==0){
                    if (!list.isEmpty()) {
                        for (SetPriority priority : list) {
                            priorityQueue.add(priority);
                        }
                    }
                    break;
                }

            }


        }
        //获取最后20%的时间发表的文章

        List<Article> timesort_define=timesort.subList(0,timesort.size()/5);

        //按照时间赋予，后发布的优先级高
        for(Article article:timesort_define) {
            List<SetPriority> list = new ArrayList<SetPriority>();
            for (int i = 0; i < articles.size(); i++) {
                SetPriority setPriority = (SetPriority) priorityQueue.remove();
                Article o = (Article) setPriority.getObject();

                if (o.get_id().equals(article.get_id())) {
                    setPriority.addPriorityLevel3(2);
                    priorityQueue.add(setPriority);
                    if (!list.isEmpty()) {
                        for (SetPriority priority : list) {
                            priorityQueue.add(priority);
                        }
                    }
                    break;
                }
                list.add(setPriority);
            }
            if (priorityQueue.size()==0){
                if (!list.isEmpty()) {
                    for (SetPriority priority : list) {
                        priorityQueue.add(priority);
                    }
                }
                break;
            }
        }
        //根据爱好访问次数排序，作者的分类
        List<View> views=viewMapper.selectByUserId(user_id);
        if(!views.isEmpty()) {
            for (View view : views) {
                List<SetPriority> list = new ArrayList<SetPriority>();

                for (int i = 0; i < articles.size(); i++) {
                    SetPriority setPriority = (SetPriority) priorityQueue.remove();
                    Article o = (Article) setPriority.getObject();


                    // Like like=JSON.parseObject(json,Like.class);


                    if (o.getCategory().equals(view.getCategory_id())) {
                        setPriority.addPriorityLevel2(view.getCount());
                        priorityQueue.add(setPriority);
                        if (!list.isEmpty()) {
                            for (SetPriority priority : list) {
                                priorityQueue.add(priority);
                            }
                        }
                        break;
                    }
                    list.add(setPriority);
                }
                if (priorityQueue.size() == 0) {
                    if (!list.isEmpty()) {
                        for (SetPriority priority : list) {
                            priorityQueue.add(priority);
                        }
                    }
                    break;
                }

            }

        }


        if(jsons!=null&&!jsons.isEmpty()){
            for(String json:jsons){
                List<SetPriority> list = new ArrayList<SetPriority>();

                for (int i = 0; i < articles.size(); i++) {
                    SetPriority setPriority = (SetPriority) priorityQueue.remove();
                    Article o = (Article) setPriority.getObject();


                    Like like=JSON.parseObject(json,Like.class);


                    if (o.getType().equals(like.getType_id())) {
                        setPriority.addPriorityLevel2(like.getCount());
                        priorityQueue.add(setPriority);
                        if (!list.isEmpty()) {
                            for (SetPriority priority : list) {
                                priorityQueue.add(priority);
                            }
                        }
                        break;
                    }
                    list.add(setPriority);
                }
                if (priorityQueue.size()==0){
                    if (!list.isEmpty()) {
                        for (SetPriority priority : list) {
                            priorityQueue.add(priority);
                        }
                    }
                    break;
                }

            }

        }
        //根据爱好的访问次数排序,系统判定的
        if(jsons!=null&&!jsons.isEmpty()){
            for(String json:jsons){
                List<SetPriority> list = new ArrayList<SetPriority>();

                for (int i = 0; i < articles.size(); i++) {
                    SetPriority setPriority = (SetPriority) priorityQueue.remove();
                    Article o = (Article) setPriority.getObject();

                    Like like=JSON.parseObject(json,Like.class);

                    if (o.getType().equals(like.getType_id())) {
                        setPriority.addPriorityLevel2(like.getCount());
                        priorityQueue.add(setPriority);
                        if (!list.isEmpty()) {
                            for (SetPriority priority : list) {
                                priorityQueue.add(priority);
                            }
                        }
                        break;
                    }
                    list.add(setPriority);
                }
                if (priorityQueue.size()==0){
                    if (!list.isEmpty()) {
                        for (SetPriority priority : list) {
                            priorityQueue.add(priority);
                        }
                    }
                    break;
                }

            }

        }


        List<String> jsons_define=null;

        //按最新的爱好录入时间排序
        if(!jsons.isEmpty()) {
            jsons_define=jsons.subList(0,jsons.size()/2);
        }

        if(jsons_define!=null&&!jsons_define.isEmpty()){
            for(String json:jsons_define){
                List<SetPriority> list = new ArrayList<SetPriority>();

                for (int i = 0; i < articles.size(); i++) {
                    SetPriority setPriority = (SetPriority) priorityQueue.remove();
                    Article o = (Article) setPriority.getObject();

                    Like like=JSON.parseObject(json,Like.class);

                    if (o.getType().equals(like.getType_id())) {
                        setPriority.addPriorityLevel3(2);
                        priorityQueue.add(setPriority);
                        if (!list.isEmpty()) {
                            for (SetPriority priority : list) {
                                priorityQueue.add(priority);
                            }
                        }
                        break;
                    }
                    list.add(setPriority);
                }
                if (priorityQueue.size()==0){
                    if (!list.isEmpty()) {
                        for (SetPriority priority : list) {
                            priorityQueue.add(priority);
                        }
                    }
                    break;
                }

            }



        }

        //获取2小时内浏览次数，如果有记录则下降优先级
        for(Article article:articles) {
            List<SetPriority> list = new ArrayList<SetPriority>();
            for (int i = 0; i < articles.size(); i++) {
                SetPriority setPriority = (SetPriority) priorityQueue.remove();
                Article o = (Article) setPriority.getObject();

                if(redisTemplate.opsForValue().get("article_"+o.get_id())!=null){
                    Integer count= Integer.parseInt((String) redisTemplate.opsForValue().get("article_"+o.get_id()));
                    setPriority.declinePriorityLevel3(count);
                    priorityQueue.add(setPriority);
                    if (!list.isEmpty()) {
                        for (SetPriority priority : list) {
                            priorityQueue.add(priority);
                        }
                    }
                    break;
                }
                list.add(setPriority);
            }
            //可能出现空队列的情况
            if (priorityQueue.size()==0){
                if (!list.isEmpty()) {
                    for (SetPriority priority : list) {
                        priorityQueue.add(priority);
                    }
                }
                break;
            }
        }

        //只返回前10条数据
        int record=articles.size();
        if(record>=10){
            record=10;
        }
        List<Article> articleList=new ArrayList<Article>();
        for(int i=0;i<record;i++){
            SetPriority setPriority= (SetPriority) priorityQueue.remove();
            Article o= (Article) setPriority.getObject();
            //记录浏览次数到redis
            if (redisTemplate.opsForValue().get("article_"+o.get_id())==null){
                Integer count=1;
                redisTemplate.opsForValue().set("article_"+o.get_id(),count.toString(),2, TimeUnit.HOURS);
            }
            else{

                Integer count= Integer.parseInt((String) redisTemplate.opsForValue().get("article_"+o.get_id()));
                count=count+1;
                String string = count.toString();
                System.out.println(string);
                System.out.println(string);
                long ttl=redisTemplate.getExpire("article_"+o.get_id());
                System.out.println(ttl);
                redisTemplate.opsForValue().set("article_"+o.get_id(),string,ttl,TimeUnit.SECONDS);

            }
            articleList.add(o);
        }

        return articleList;
    }


}
